package exp;

import utils.BasicJPanel;
import utils.VFlowLayout;

import javax.swing.*;
import javax.swing.border.TitledBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Random;

public class saltAndPepperNoiseJPanel extends BasicJPanel implements ChangeListener
{
    private final JLabel imageJLabel;
    private final JLabel noiseJLabel;
    private final JLabel filterJLabel;
    private final JLabel minusJLabel;

    private final JSpinner whiteJSpinner;
    private final JSpinner blackJSpinner;

    public saltAndPepperNoiseJPanel()
    {
        super();
        setLayout(new BorderLayout());
                {
            JPanel jPanel=new JPanel();
            add(jPanel);
            jPanel.setLayout(new GridLayout(2,2));
            jPanel.add(imageJLabel=new JLabel());
            jPanel.add(noiseJLabel=new JLabel());
            jPanel.add(filterJLabel=new JLabel());
            jPanel.add(minusJLabel=new JLabel());
        }

        JPanel infoJPanel=new JPanel();
        infoJPanel.setBorder(new TitledBorder("操作"));
        JScrollPane jScrollPane=new JScrollPane(infoJPanel);
        jScrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
        add(jScrollPane,BorderLayout.WEST);
        infoJPanel.setLayout(new VFlowLayout());

        infoJPanel.add(whiteJSpinner=new JSpinner(new SpinnerNumberModel(20,0,100,1)));
        whiteJSpinner.addChangeListener(this);
        infoJPanel.add(blackJSpinner=new JSpinner(new SpinnerNumberModel(20,0,100,1)));
        blackJSpinner.addChangeListener(this);
    }

    private void update()
    {
        final Random random=new Random();
        final BufferedImage src=(BufferedImage)((ImageIcon)imageJLabel.getIcon()).getImage();
        final int blackNoise=((Number)blackJSpinner.getValue()).intValue();
        final int whiteNoise=((Number)whiteJSpinner.getValue()).intValue();
        final BufferedImage noise=new BufferedImage(src.getWidth(),src.getHeight(),BufferedImage.TYPE_INT_RGB);
        final BufferedImage filter=new BufferedImage(src.getWidth(),src.getHeight(),BufferedImage.TYPE_INT_RGB);
        final BufferedImage minus=new BufferedImage(src.getWidth(),src.getHeight(),BufferedImage.TYPE_INT_RGB);
        //加噪声部分
        for(int i=0;i<src.getHeight();++i)
            for(int j=0;j<src.getWidth();++j)
            {
                int rgb=src.getRGB(j,i);
                if(blackNoise>random.nextInt(100))
                    rgb=0X000000;
                if(whiteNoise>random.nextInt(100))
                    rgb=0XFFFFFFF;
                noise.setRGB(j,i,rgb);
            }
        //滤波部分
        {
            int[][] f={{1,1,1},{1,1,1},{1,1,1}};

            int sum=0;
            for(int k=0;k<3;++k)
                for(int l=0;l<3;++l)
                    sum+=f[k][l];

            for(int i=1;i<src.getHeight()-1;++i)
                for(int j=1;j<src.getWidth()-1;++j)
                {
                    int sumR=0,sumG=0,sumB=0;
                    for(int k=0;k<3;++k)
                        for(int l=0;l<3;++l)
                        {
                            int rgb=noise.getRGB(j-1+l,i-1+k);
                            sumR+=((rgb>>16)&0XFF)*f[l][k];
                            sumG+=((rgb>>8)&0XFF)*f[l][k];
                            sumB+=((rgb)&0XFF)*f[l][k];
                        }
                    sumR/=sum;
                    sumG/=sum;
                    sumB/=sum;
                    int rgb=((sumR&0XFF)<<16)|((sumG&0XFF)<<8)|((sumB&0XFF));
                    filter.setRGB(j,i,rgb);
                }
        }
        for(int i=0;i<src.getHeight();++i)
            for(int j=0;j<src.getWidth();++j)
            {
                final int rgb1=src.getRGB(j,i);
                final int r1=(rgb1>>16)&0XFF;
                final int g1=(rgb1>>8)&0XFF;
                final int b1=(rgb1)&0XFF;

                final int rgb2=filter.getRGB(j,i);
                final int r2=(rgb2>>16)&0XFF;
                final int g2=(rgb2>>8)&0XFF;
                final int b2=(rgb2)&0XFF;

                minus.setRGB(j,i,((Math.abs(r1-r2)&0XFF)<<16)|((Math.abs(g1-g2)&0XFF)<<8)|((Math.abs(b1-b2)&0XFF)));
            }
        noiseJLabel.setIcon(new ImageIcon(noise));
        filterJLabel.setIcon(new ImageIcon(filter));
        minusJLabel.setIcon(new ImageIcon(minus));
    }

    public void update(Path path) throws IOException, BmpStructureErrorException
    {
        final Bmp bmp=new Bmp(path);
        imageJLabel.setIcon(new ImageIcon(bmp.getImage()));
        update();
    }

    public String getButtonName()
    {
        return "<html>第6章选做1：椒盐噪声<br>第6章选做2：均值滤波</html>";
    }

    public void stateChanged(ChangeEvent e)
    {
        update();
    }
}
